use std::cell::{RefCell, RefMut};
use std::collections::HashMap;
use std::ops::Deref;
use std::rc::Rc;

use crate::class_file::byte_data_reader::ByteDataReader;
use crate::get_constant_info_from_vm_class;
use crate::heap::vm_heap::VMHeap;
use crate::instruction::instruction::Instruction;
use crate::class::vm_access_flags::{is_final, is_static};
use crate::class::vm_class::VMClass;
use crate::class::vm_class_constant_info::VMClassConstantInfoEnum;
use crate::vm_object::VMObject;
use crate::vm_thread::{VMFrame, VMThread};
use crate::vm_val::VMValEnum;

pub struct new {
    pub val: u16,
}

impl Instruction for new {
    fn read_operands(&mut self, frame: Rc<RefCell<VMFrame>>) {
        self.val = frame.borrow_mut().read_u16();
    }

    fn exec(&mut self, frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {
        let class_name = {
            let mut rw_frame = frame.borrow_mut();
            let ro_constant_pool = rw_frame.current_vm_class.constant_pool.borrow();
            let constant_info_option = ro_constant_pool.get(self.val as usize);
            if constant_info_option.is_none() {
                panic!("常量池索引异常")
            }
            match constant_info_option.unwrap().clone().deref() {
                VMClassConstantInfoEnum::VMClassConstantInfoClass { val } => {
                    String::from(&val.name)
                }
                _ => { panic!("类加载失败") }
            }
        };
        let mut rw_class_loader = thread.vm.class_loader.borrow_mut();
        let load_class_result = rw_class_loader.load_class(&class_name);
        if load_class_result.is_err() {
            panic!("{},{},{}", file!(), line!(), load_class_result.err().unwrap());
        }
        let vm_class = load_class_result.unwrap();
        // 初始化class
        if !vm_class.has_init() {
            VMClass::init(vm_class.clone(), frame, thread);
        } else {
            let mut rw_frame = frame.borrow_mut();
            let new_vmobject_result = VMHeap::new_object(vm_class.clone());
            if new_vmobject_result.is_err() {
                panic!("err:{}", new_vmobject_result.err().unwrap());
            }
            let obj = new_vmobject_result.unwrap();
            rw_frame.operand_stack.borrow_mut().push(obj);
        }
    }

    fn to_string(&self) -> String {
        String::from("new")
    }
}


pub struct anewarray {
    pub index: u16,
}

impl Instruction for anewarray {
    fn read_operands(&mut self, frame: Rc<RefCell<VMFrame>>) {
        self.index = frame.borrow_mut().read_u16();
    }

    fn exec(&mut self, frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {
        let mut rw_frame = frame.borrow_mut();
        let class_ref = get_constant_info_from_vm_class!(
            rw_frame.current_vm_class, self.index, VMClassConstantInfoClass);

        let arr_class = {
            let mut rw_class_loader = thread.vm.class_loader.borrow_mut();

            let comment_class_load_result = rw_class_loader.load_class(&class_ref.name);
            if comment_class_load_result.is_err() {
                panic!("类加载失败:{},{},{}", file!(), line!(), comment_class_load_result.err().unwrap());
            }

            let arr_cls_name = format!("[L{};", &class_ref.name);
            let load_class_result = rw_class_loader.load_class(&arr_cls_name);
            if load_class_result.is_err() {
                panic!("{},{},{}", file!(), line!(), load_class_result.err().unwrap())
            }
            load_class_result.unwrap()
        };
        let mut rw_operand_stack = rw_frame.operand_stack.borrow_mut();
        let arr_len = {
            let arr_len_enum = rw_operand_stack.pop().unwrap();
            VMValEnum::convert2integer(&arr_len_enum).num
        };

        let obj = VMHeap::new_array_object(arr_class, arr_len).unwrap();
        rw_operand_stack.push(obj);
    }

    fn to_string(&self) -> String {
        String::from("anewarray")
    }
}


pub const AT_BOOLEAN: u8 = 4;
pub const AT_CHAR: u8 = 5;
pub const AT_FLOAT: u8 = 6;
pub const AT_DOUBLE: u8 = 7;
pub const AT_BYTE: u8 = 8;
pub const AT_SHORT: u8 = 9;
pub const AT_INT: u8 = 10;
pub const AT_LONG: u8 = 11;

pub struct newarray {
    pub atype: u8,
}

impl Instruction for newarray {
    fn read_operands(&mut self, frame: Rc<RefCell<VMFrame>>) {
        self.atype = frame.borrow_mut().read_u8();
    }

    fn exec(&mut self, frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {
        let ro_frame = frame.borrow();
        let arr_class_name = self.get_primitive_arr_class_name(self.atype);
        let mut rw_class_loader = thread.vm.class_loader.borrow_mut();

        let arr_vm_class_result = rw_class_loader.load_class(&arr_class_name);
        if arr_vm_class_result.is_err() {
            panic!("{},{},{}", file!(), line!(), arr_vm_class_result.err().unwrap());
        }
        let mut rw_operand_stack = ro_frame.operand_stack.borrow_mut();
        let arr_len = {
            let arr_len_enum = rw_operand_stack.pop().unwrap();
            VMValEnum::convert2integer(&arr_len_enum).num
        };
        let arr_vm_class = arr_vm_class_result.unwrap();

        let obj = VMHeap::new_array_object(arr_vm_class, arr_len).unwrap();

        rw_operand_stack.push(obj);
    }

    fn to_string(&self) -> String {
        String::from("newarray")
    }
}

impl newarray {
    fn get_primitive_arr_class_name(&self, atype: u8) -> String {
        match atype {
            AT_BOOLEAN => { "[Z".to_string() }
            AT_BYTE => { "[B".to_string() }
            AT_CHAR => { "[C".to_string() }
            AT_SHORT => { "[S".to_string() }
            AT_INT => { "[I".to_string() }
            AT_LONG => { "[J".to_string() }
            AT_FLOAT => { "[F".to_string() }
            AT_DOUBLE => { "[D".to_string() }
            _ => {
                panic!("{},{},异常atype:{}", file!(), line!(), atype)
            }
        }
    }
}